// =====================================================================================
//
//       Filename:  application.h
//
//    Description:  Définition des objets communs de l'application (hors interfaces
//					spécifiques)
//
//        Version:  1.0
//        Created:  26/08/2009 15:49:00
//       Revision:  none
//       Compiler:  g++
//
//         Author:  François Hissel (fh), francois.hissel@m4x.org
//        Company:
//
// =====================================================================================

#ifndef APPLICATION_H_INC
#define APPLICATION_H_INC

#include	<iostream>
#include	<string>
#include	<list>
#include	"erreurs.h"
#include	"config.h"
#include	"raster.h"
#include	"geometrie.h"
#include	"graphe.h"
#include	"attributs.h"
#include	"gisobjects.h"
#include	"routes.h"

using namespace std;

/**
 * \enum MessageType
 * \brief Représentation des types de message affichés par l'application
 *
 * L'énumération indique les valeurs possibles des types de message affichés par l'application. Ces valeurs peuvent être utilisées pour paramétrer la façon dont l'application affiche les messages, à travers la surcharge des fonctions Application::affiche et Application::affiche_erreur
 */
enum MessageType {
	NUL,	//!< Indique qu'aucun message ne doit être affiché
	INFORMATION,	//!< Message d'information
	ERREUR,	//!< Message d'erreur
	TEXTE	//!< Représente un message qui ne doit être affiché qu'en mode texte
};

/**
 * \brief Définition d'un type de pointeur de fonction d'affichage
 *
 * Le type DisplayProc est un pointeur vers une fonction d'affichage, qui est utilisée par l'application pour informer l'utilisateur de son fonctionnement. Par défaut, en mode console, la fonction écrit sur la sortie standard et sur le flux d'erreur standard. Si l'interface graphique est chargée, le pointeur peut être redirigé vers une autre fonction d'affichage.
 * \param message Message à afficher
 * \param type Code représentant le type du message
 * \param titre Titre du message, par défaut nul
 */
typedef void (*DisplayProc)(const string &message,MessageType type,const string &titre);

/**
 * \class Application
 * \brief Classe de définition des objets et des fonctions de l'application
 *
 * La classe regroupe l'ensemble des objets et des méthodes utilisées par la couche de calcul de l'application, sans traiter de l'interface. Elle sert d'intermédiaire entre la couche algorithmique et l'interface utilisateur.
 */
class Application {
	public:
		static const int MAX_TAILLE=1000;	//!< Taille maximale des grilles raster
		int argc;	//!< Nombre de paramètres de la ligne de commande
		char **argv;	//!< Paramètres de la ligne de commande
		DisplayProc affiche;	//!< Pointeur vers la fonction d'affichage standard
		DisplayProc affiche_erreur;	//!< Pointeur vers la fonction d'affichage d'un message d'erreur
		Reseau *reseau;	//!< Réseau routier associé
		Raster *raster;	//!< Couche raster associée
		list<Ponctuel*> sources;	//!< Liste des sources utilisées dans le calcul de l'accessibilité
		list<Ponctuel*> enjeux;	//!< Liste des enjeux à desservir
		bool calcule_raster;	//!< Indique si les sources ont été modifiées, ce qui nécessite un nouveau parcours du réseau par l'algorithme de Dijkstra pour évaluer les distances des sommets à ces sources
		double wxmin;	//!< Abscisse minimale de la zone affichée
		double wymin;	//!< Ordonnée minimale de la zone affichée
		double wxmax;	//!< Abscisse maximale de la zone affichée
		double wymax;	//!< Ordonnée maximale de la zone affichée
		double w_xmin;	//!< Abscisse minimale souhaitée de la zone affichée
		double w_xmax;	//!< Abscisse maximale souhaitée de la zone affichée
		double w_ymin;	//!< Ordonnée minimale souhaitée de la zone affichée
		double w_ymax;	//!< Ordonnée maximale souhaitée de la zone affichée
		double ratio;	//!< Ratio d'affichage, rapport entre les coordonnées affichées et les coordonnées réelles. Correspond à un facteur de zoom : plus le ratio est grand, plus la zone affichée est petite.
		list<Point> echelles;	//!< Liste des échelles utilisées pour le calcul de l'inondation
		list<double> niveaux;	//!< Liste des niveaux d'eau aux échelles définies par la variable Application::echelles
		int max_width;	//!< Largeur maximale en pixels des fichiers PNG à créer
		int max_height;	//!< Hauteur maximale en pixels des fichiers PNG à créer
		int raster_size;	//!< Taille des grilles raster générées pour l'export au format PNG (en nombre de points)
		bool affiche_legende;	//!< Indique si une legende doit être ajoutée aux cartes raster exportées
		string import_mif;	//!< Nom du fichier au format MapInfo MIF à partir duquel importer les données cartographiques
		string import_mid;	//!< Nom du fichier au format MapInfo MID à partir duquel importer les données concernant les attributs
		list<string> affichage_troncon;	//!< Noms des champs à afficher pour représenter un tronçon de route
		Config config;	//!< Paramètres de configuration supplémentaires, utilisés pour l'interprétation des fichiers d'entrée et la construction du graphe

		/**
		 * \brief Constructeur standard
		 *
		 * Le constructeur initialise le contexte d'application, en indiquant les paramètres principaux de configuration.
		 * \param pargc Nombre d'arguments de la ligne de commande
		 * \param pargv Arguments de la ligne de commande, utilisés pour configurer certains comportements de l'application
		 * \param paffiche Pointeur vers la fonction d'affichage standard
		 * \param paffiche_erreur Pointeur vers la fonction d'affichage d'un message d'erreur
		 */
		Application(int pargc,char **pargv,DisplayProc paffiche,DisplayProc paffiche_erreur);

		~Application();	//!< Destructeur standard

		/**
		 * \brief Retourne la table descriptive des sources
		 *
		 * La méthode d'accès retourne un pointeur vers la table descriptive des sources. Elle est utilisée lorsqu'on veut créer une nouvelle source.
		 * \return Pointeur vers la table descriptive des sources
		 */
		DescriptionTable *dtsource() {return _dtsource;}

		/**
		 * \brief Retourne la table descriptive des enjeux
		 *
		 * La méthode d'accès retourne un pointeur vers la table descriptive des enjeux. Elle est utilisée lorsqu'on veut créer un nouvel enjeu.
		 * \return Pointeur vers la table descriptive des enjeux
		 */
		DescriptionTable *dtenjeu() {return _dtenjeu;}

		/**
		 * \brief Ajoute une nouvelle source
		 *
		 * La méthode ajoute une nouvelle source à la liste en mémoire et définit ses arguments
		 * \param px Abscisse de la source
		 * \param py Ordonnée de la source
		 * \param pnom Nom de la source
		 */
		void ajoute_source(double px,double py,string pnom);

		/**
		 * \brief Vide la liste des sources
		 *
		 * La méthode vide la liste des sources et libère la mémoire occupée.
		 */
		void vide_sources();

		/**
		 * \brief Ajoute un nouvel enjeu
		 *
		 * La méthode ajoute un nouvel enjeu à la liste en mémoire et définit ses arguments
		 * \param px Abscisse de l'enjeu
		 * \param py Ordonnée de l'enjeu
		 * \param pnom Nom de l'enjeu
		 */
		void ajoute_enjeu(double px,double py,string pnom);

		/**
		 * \brief Vide la liste des enjeux
		 *
		 * La méthode vide la liste des enjeux et libère la mémoire occupée.
		 */
		void vide_enjeux();

		/**
		 * \brief Calcul de la cote d'eau en un point par interpolation à partir de la projection sur une polyligne
		 *
		 * La méthode projette le point spécifié par les arguments x et y sur la polyligne Application::echelles, puis évalue la cote de l'eau en ce point par interpolation linéaire en supposant que les cotes d'eau aux sommets constitutifs de la polyligne sont données par Application::niveaux.
		 * \param x Abscisse du point où calculer la cote d'eau
		 * \param y Ordonnée du point où calculer la cote d'eau
		 * \return Niveau d'eau estimé par interpolation linéaire
		 */
		double evalue_cote(double x,double y);

		/**
		 * \brief Mise à jour des poids des arcs du réseau pour un niveau d'eau donné
		 *
		 * La méthode met à jour la propriété des tronçons de routes qui indique s'ils sont coupés, en se référant aux niveaux d'eau définis par la polyligne Application::echelles et les valeurs Application::niveaux.
		 * \param champ_zini Indice du champ de la table des attributs qui correspond à l'altitude du début du tronçon de route
		 * \param champ_zfin Indice du champ de la table des attributs qui correspond à l'altitude de la fin du tronçon de route
		 */
		void actualise_coupure(int champ_zini,int champ_zfin);

		/**
		 * \brief Calcul des poids des arcs du graphe
		 *
		 * La méthode recalcule les poids des arcs du graphe en tenant compte du niveau d'eau représenté par les variables Application::echelles et Application::niveaux.
		 */
		void calcule_poids();

		/**
		 * \brief Affichage d'un itinéraire entre deux points
		 *
		 * La méthode calcule le meilleur itinéraire entre deux points par l'algorithme A* puis indique les noeuds traversés.
		 * \param s1 Sommet initial
		 * \param s2 Sommet final
		 */
		void cherche_itineraire(Sommet* s1,Sommet* s2);

		/**
		 * \brief Affichage d'un itinéraire entre deux points
		 *
		 * La méthode calcule le meilleur itinéraire entre deux points par l'algorithme A* puis indique les noeuds traversés.
		 * \param x1 Abscisse du noeud d'origine
		 * \param y1 Ordonnée du noeud d'origine
		 * \param x2 Abscisse du noeud de destination
		 * \param y2 Ordonnée du noeud de destination
		 */
		void cherche_itineraire(double x1,double y1,double x2,double y2);

		/**
		 * \brief Récupère la liste des arcs composant l'itinéraire entre 2 points
		 *
		 * \param x1 Abscisse du noeud d'origine
		 * \param y1 Ordonnée du noeud d'origine
		 * \param x2 Abscisse du noeud de destination
		 * \param y2 Ordonnée du noeud de destination
		 */
		list<Arc*> Application::get_itineraire(double x1,double y1,double x2,double y2);

		/**
		 * Récupère la liste des arcs composant l'itinéraire entre 2 sommets
		 *
		 * \param s1 Sommet initial
		 * \param s2 Sommet final
		 */
		list<Arc*> Application::get_itineraire(Sommet* s1,Sommet* s2);

		/**
		 * \brief compare les itinéraires avec et sans eau entre les points (x1,y1) et (x2,y2)
		 *
		 * La méthode colorie les arcs du graphe en vert s'ils sont identiques entre les 2 itinéraires ou s'ils appartiennent à l'itinéraire à emprunter avec le niveau d'eau paramétré.
		 * Les arcs composant l'itinéraire sans eau qui sont rendus inaccessibles par le niveau d'eau courant sont colorés en rouge.
		 * Ces changements de couleur sont visibles quand on exporte la carte en PNG.
		 */
		void Application::compare_itineraire(double x1,double y1,double x2,double y2);

		/**
		 * \brief Calcul de la tournée la plus courte depuis la première source référencée par Application::sources.front() vers l'ensemble des enjeux définis par Application::enjeux
		 *
		 * La méthode calcule la tournée optimale pour desservir l'ensemble des enjeux en un temps minimum. Elle utilise un algorithme de colonie de fourmis, qui s'exécute en un temps proportionnel au nombre d'enjeux. Pour la constitution du réseau et le calcul des distances, la méthode fait appel à l'algorithme de Dijkstra Graphe::dijkstra_graphe à partir de chacun des enjeux. La complexité totale est donc O(mnp) avec m le nombre d'enjeux, n le nombre de carrefours du réseau, et p le nombre de tronçons de routes. La tournée optimale est affichée à l'écran, et visualisée sur la carte vectorielle par des traits de couleur.
		 * \param mode Algorithme à utiliser pour le calcul : 0 pour un choix automatique en fonction du nombre d'enjeux, 1 pour l'algorithme de parcours systématique dont la complexité est exponentielle, 2 pour l'algorithme de simulation des colonies de fourmis. La valeur par défaut est 0.
		 * \param nb_iter Nombre d'itérations si l'algorithme des colonies de fourmis est utilisé, par défaut 20.
		 * \param nb_fourmis Nombre de fourmis à simuler à chaque itération, par défaut 800.
		 * \param alpha Paramètre d'attractivité des phéromones : plus il est grand, plus les fourmis auront tendance à privilégier les chemins déjà chargés en phéromones. La valeur par défaut est 1.
		 * \param beta Paramètre de visibilité : plus il est grand, plus les fourmis auront tendance à privilégier les sommets les plus proches lors de leur parcours aléatoire du réseau. Ce paramètre équilibre le précédent. La valeur par défaut est 2.
		 * \param rho Paramètre d'évaporation : indique quelle proportion de phéromones s'évapore de chaque tronçon après la fin d'une itération. La valeur par défaut est 0,2.
		 */
		void calcule_tournee(int mode,int nb_iter,int nb_fourmis,double alpha,double beta,double rho);

		/*
		 * Cette fonction renvoie l'affichage sous forme heures, minutes, secondes du temps en minutes passé en paramètre
		 */
		string Application::convert_time(double temps_minutes);

		/**
		 * \brief Calcule la carte d'accessibilité et de desserte
		 *
		 * La méthode lance l'algorithme de Dijkstra sur le réseau afin de calculer la distance de chaque sommet à l'une des sources. Elle met également à jour le membre Intersection::tag de chaque sommet avec le numéro de la source qui dessert le sommet considéré.
		 */
		void calcule_desserte();

		/**
		 * \brief Dessine la carte d'accessibilité à partir des distances stockées dans les sommets du réseau
		 *
		 * La méthode dessine la carte d'accessibilité à partir des distances aux sources stockées dans la variable Sommet::dist et l'enregistre dans la structure de données raster. Seule la zone comprise dans les frontières du zoom est dessinée. La résolution de la grille est fixée grâce au paramètre resolution.
		 * Pour les points en dehors du réseau (la majorité des points de la carte raster), une projection sur le réseau est effectuée. La méthode calcule alors la distance à la source par une combinaison linéaire des distances aux trois plus proches voisins.
		 * \param resolution Résolution de la grille à exporter, correspondant à une distance sur le terrain
		 * \param vmax Valeur plafond des données raster à représenter. Le tracé considérera que toutes les valeurs sont comprises entre 0 et vmax. Si une valeur est en dehors de ces frontières, elle sera représentée par un point gris sur la carte. Sinon sa couleur sera placée sur une échelle de couleur prédéfinie.
		 */
		void dessine_accessibilite(double resolution,double vmax);

		/**
		 * \brief Dessine la carte de desserte à partir des numéros de sources stockés dans les sommets du réseau
		 *
		 * La méthode dessine la carte de desserte à partir des numéros de sources stockés dans la variable Sommet::tag et l'enregistre dans la structure de données raster. Seule la zone comprise dans les frontières du zoom est dessinée. La résolution de la grille est fixée grâce au paramètre resolution.
		 * \param resolution Résolution de la grille à exporter, correspondant à une distance sur le terrain
		 */
		void dessine_desserte(double resolution);

		/**
		 * \brief Dessine la carte des cotes d'eau
		 *
		 * La méthode dessine la carte des cotes d'eau et l'enregistre dans la structure de données raster. Seule la zone comprise dans les frontières du zoom est dessinée.
		 * \param resolution Résolution de la grille à exporter, correspondant à une distance sur le terrain
		 * \param vmax Valeur plafond des données raster à représenter. Le tracé considérera que toutes les valeurs sont comprises entre 0 et vmax. Si une valeur est en dehors de ces frontières, elle sera représentée par un point gris sur la carte. Sinon sa couleur sera placée sur une échelle de couleur prédéfinie.
		 */
		void dessine_cote(double resolution,double vmax);

		/**
		 * \brief Exporte la carte raster vers un fichier au format ArcInfo ASCII
		 *
		 * La méthode exporte la carte raster précédemment calculée dans un fichier au format ArcInfo ASCII spécifié en argument.
		 * \param fichier Nom du fichier
		 */
		void exporte_raster(string fichier) const;

		/**
		 * \brief Importe une carte raster depuis un format ArcInfo ASCII
		 *
		 * La méthode importe un fichier raster, représentant en particulier un modèle numérique de terrain, depuis un fichier au format ArcInfo ASCII spécifié en argument.
		 * \param fichier Nom du fichier
		 */
		void importe_raster(string fichier);

		/**
		 * \brief Calcule le ratio de l'affichage à partir des frontières souhaités
		 *
		 * La fonction recalcule le ratio de l'affichage à partir des dimensions souhaitées de la carte affichée. Si celles-ci n'existent pas, la carte entière est affichée.
		 * \param maxwidth Indication de largeur pour la carte affichée
		 * \param maxheight Indication de hauteur pour la carte affichée
		 * \param fixed Indique si les dimensions indiquées correspondent strictement à la taille de la carte affichée, ou si celle-ci sera ajustée en fonction du ratio. Lorsque fixed vaut True, la portion de la carte affichée contient au moins la zone définie par les paramètres w_xmin, w_xmax, w_ymin et w_ymax mais pourra être plus étendue dans la dimension la moins contrainte. Si fixed vaut False, la zone affichée sera exactement la zone définie par les variables w_xmin, w_xmax, w_ymin et w_ymax mais les dimensions de la carte sont susceptibles de changer.
		 */
		void calcule_ratio(int maxwidth,int maxheight,bool fixed);

		/**
		 * \brief Conversion d'une abscisse réelle vers une abscisse de la fenêtre en cours
		 *
		 * La fonction convertit, par une transformation linéaire, l'abscisse réelle d'un point vers une abscisse utile pour le tracé dans la fenêtre. Elle utilise le ratio d'affichage calculé précédemment.
		 * \param x Abscisse à convertir
		 * \return Abscisse résultante pour le tracé
		 */
		int get_x(double x) const {return (int)((x-wxmin)*ratio);}

		/**
		 * \brief Conversion d'une ordonnée réelle vers une ordonnée de la fenêtre en cours
		 *
		 * La fonction convertit, par une transformation linéaire, l'ordonnée réelle d'un point vers une ordonnée utile pour le tracé dans la fenêtre. Elle utilise le ratio d'affichage calculé précédemment.
		 * \param y Ordonnée à convertir
		 * \return Ordonnée résultante pour le tracé
		 */
		int get_y(double y) const {return (int)((wymax-y)*ratio);}

		/**
		 * \brief Conversion d'une abscisse d'affichage vers une abscisse réelle
		 *
		 * La fonction convertit, par une transformation linéaire, l'abscisse sur l'écran vers une abscisse réelle. Elle utilise le ratio d'affichage calculé précédemment.
		 * \param x Abscisse à convertir
		 * \return Abscisse réelle résultante
		 */
		double get_xr(double x) const {return x/ratio+wxmin;}

		/**
		 * \brief Conversion d'une ordonnée d'affichage vers une ordonnée réelle
		 *
		 * La fonction convertit, par une transformation linéaire, l'ordonnée sur l'écran vers une ordonnée réelle. Elle utilise le ratio d'affichage calculé précédemment.
		 * \param y Ordonnée à convertir
		 * \return Ordonnée réelle résultante
		 */
		double get_yr(double y) const {return wymax-y/ratio;}

		/**
		 * Permet d'exporter le réseau routier complet en SVG dans le fichier passé en paramètre
		 */
		void Application::exporte_svg(string fichier);

	private:
		DescriptionTable *_dtsource;	//!< Description des attributs d'un service de secours (source)
		DescriptionTable *_dtenjeu;	//!< Description des attributs d'un enjeu
};

#endif /* APPLICATION_H_ */
